package Groep1;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.naming.NamingException;

/**
 * Connection class is voor de connectie met een client.
 * 
 * @version 1.1 5 Jun 2008
 * @author Roy Esselink & Brian Bolks
 */
public class Connnection implements Runnable {

	// Client socket
	private Socket socket;
	private String remoteHost;

	DataOutputStream toClient;
	BufferedReader fromClient;

	/**
	 * Constructor Connection, start de verbinding met de client.
	 * 
	 * @param s
	 * @param serv
	 */
	public Connnection(Socket s) {
		socket = s;
	}

	/**
	 * Method run, start het ontvangen van de client berichten.
	 * 
	 */
	public void run() {
		processConnection();
	}

	private void processConnection() {
		boolean quit = false;
		String requestCommand;

		try {
			InputStream is = socket.getInputStream();
			toClient = new DataOutputStream(socket.getOutputStream());

			InputStreamReader sr = new InputStreamReader(is);
			fromClient = new BufferedReader(sr);
		} catch (IOException e) {
			System.out.println("Initialization error: " + e);
		}

		 InetAddress localHost = null;
		try {
			localHost = InetAddress.getLocalHost();
		} catch (UnknownHostException e1) {
		}
		//localHost = socket.getLocalAddress().toString();
		remoteHost = socket.getRemoteSocketAddress().toString();

		reply("220 " + localHost.getHostAddress() + " SMTP Service Ready");

		mailMessage msg = new mailMessage();
		
		boolean heloSend = false, reciptien = false, sender = false;
		
		while (!quit) {
			requestCommand = fetch();

			System.out.println("Data: " + requestCommand);
			
			try {

				if(requestCommand == null || requestCommand.length() < 4) {
					reply("500 Syntax error, command unrecognized");	
				}
				else if (requestCommand.substring(0, 4).toUpperCase().equals("HELO")) {
					
					msg = null;
					msg = new mailMessage(requestCommand.substring(5,
							requestCommand.length()));
					
					reply("250 localhost Hello " + msg.getHelo());
					
					heloSend = true;
					
				} else if (requestCommand.substring(0, 4).toUpperCase().equals("QUIT")) {

					msg = null;
					heloSend = false;
					reciptien = false;
					sender = false;
					quit = true;
					
				} else if (requestCommand.substring(0,4).toUpperCase().equals("DATA") && heloSend) {
					
					if(sender && reciptien) {
						reply("354 Start mail input; end with <CRLF>.<CRLF>");
						
						String data = fetch();
						
						if(data.startsWith("Subject:")){
							msg.setSubject(data.substring(8));
							System.out.println(data.substring(8));	
						}else{
							msg.setBody(data);
						}
						
						while(!data.equals(".") ){				
							data = fetch();
							msg.setBody(data);
							System.out.println(data);
							
						}
						
						msg.Send(remoteHost);
						reply("250 2.6.0 Queued mail for delivery");
					}
					else {
						reply("503 5.5.2 Need mail command");
					}
					
				} else if (heloSend && requestCommand.length() > 8 && requestCommand.substring(0, 8).toUpperCase().equals("RCPT TO:")) {
	
					Pattern pattern = Pattern
							.compile("((([a-z0-9A-Z]|_|-|\\.)+)@(([a-z0-9A-Z]|/|_|-|\\.)+)\\.(([a-z0-9A-Z])+))");
					Matcher matcher = pattern.matcher(requestCommand);
			        while (matcher.find()) {
			        	msg.setReciptien(matcher.group());
			        	remoteHost = getMXhost(matcher.group());
			        	System.out.println(matcher.group());
			    
					        reply("250 2.1.5 Recipient OK");
					        reciptien = true;
			        	
			        }
		
			        
				} else if (requestCommand.length() > 10 && requestCommand.substring(0, 10).toUpperCase().equals("MAIL FROM:") && heloSend) {

					Pattern pattern = Pattern
							.compile("((([a-z0-9A-Z]|_|-|\\.)+)@(([a-z0-9A-Z]|/|_|-|\\.)+)\\.(([a-z0-9A-Z])+))");
					Matcher matcher = pattern.matcher(requestCommand);
			        while (matcher.find()) {
			            msg.setSender(matcher.group());
			            System.out.println(matcher.group());

					        reply("250 2.1.0 Sender OK");
					        
					        sender = true;
			        }
			        

			        
				} 
				else
					reply("500 Syntax error, command unrecognized");

			} catch (Exception ex) {
				ex.printStackTrace();
			}

		}

		try {
			reply("221 " + localHost
					+ " SMTP Service closing transmission channel");
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		/* Send */

	}

	/* This method fetch every line from the client */
	private String fetch() {
		String message = "";
		try {
			do {
				message = fromClient.readLine();


				if (message == null)
					break;

			} while (message.length() < 0);
		} catch (Exception e) {
			System.out.println("Read socket error: " + e);
		}

		
		try { 
			if (message == null) { 
				socket.close(); 
				return "QUIT"; 
			} 
		} catch (IOException e) { 
			System.out.println("Close connection error: " + e); 
		}
		 
		return message;
	}

	private void reply(String command) {
		try {
			if (!socket.isClosed())
				toClient.writeBytes(command + "\n\r");
		} catch (IOException e) {
			System.out.println("Write socket error: " + e);
		}
		System.out.println(command);
		return;
	}
	
	private String getMXhost(String domain){
		String[] host = domain.split("@");
		String[] mxURL = null;
        try {
			mxURL = MailHostsLookup.lookupMailHosts(host[1]);
			System.out.println(mxURL[0]);
		} catch (NamingException e)
        {
            System.err.println("ERROR: No DNS record for '" + domain + "'");
        }
		return mxURL[0];
	}
}
